home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Gold Collection
/
Software Vault - The Gold Collection (American Databankers) (1993).ISO
/
cdr05
/
xnot12a.zip
/
MAIN.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-06-16
|
22KB
|
901 lines
#include "jam.h"
#include "stdlib.h"
/*
* Mainline
*/
#include "stdio.h"
#include "def.h"
#include "keyname.h"
#include "kbd.h"
#include "macro.h"
#include "malloc.h"
#ifdef SomeUnix
# include <unistd.h>
#endif
#ifdef FAT
# include <io.h>
#endif
int preload_ = TRUE; /* bad location, control prompt-preload */
int thisflag; /* Flags, this command */
int lastflag; /* Flags, last command */
int curgoal; /* Goal column */
BUFFER *curbp; /* Current buffer */
EWINDOW *curwp; /* Current window */
BUFFER *bheadp; /* BUFFER listhead */
EWINDOW *wheadp = (EWINDOW *)NULL; /* WINDOW listhead */
char pat[NPAT]; /* Pattern */
char *homedir;
BOOL showtouchedlines = TRUE;
BOOL somemail = FALSE;
char *g_APPNAME = AppName;
#ifndef WINDOWED
static char startdir[NFILEN]; /* original directory */
#endif
extern char prompt[], *promptp; /* delayed prompting */
#define ALIVE 0
#define DIED 1
#define KILLED 2
static killed = ALIVE;
static VOID rn_(edinit,(void));
static int rn_(ReadAlarmFile, (char *dir, BOOL append));
static char *path; /* point to startup dir */
/* Change the entry point to allow various Window-based pre-startup
* code to be executed first. Don't forget, if running in a Window,
* EMACS thinks the window is just a terminal, and we like it that way.
* This EMACS is minimally Windows-aware...
*/
#ifdef WINDOWED
VOID EmaxMain(argc, argv)
#else
VOID main(argc, argv)
#endif
int argc;
char **argv;
{
char *cp, *loadfile = NULL;
BOOL flag;
/* parse incoming args for startup dir
*/
path = (char *)0;
if (argv[0] && *argv[0]) /* our EXE name */
{
register int i;
path = argv[0];
i = strlen(path)-1;
/* go to first \ backwards
*/
for (; path[i]; i--)
if (path[i] == BDC1)
{
path[i+1] = '\0';
break;
}
}
/* see if can find home
*/
homedir = getenv("HOME");
if (!homedir || !*homedir) /* try to make sure have one! */
homedir = path;
if (!homedir || !*homedir)
{
static char lastresort[2];
lastresort[0] = BDC1;
lastresort[1] = '\0';
homedir = lastresort;
}
#ifdef SYSINIT
SYSINIT; /* system dependent. */
#endif
vtinit(); /* Virtual terminal. */
dirinit(); /* Get current directory */
#ifndef WINDOWED
/* In DOS land, want to restore original
* directory to shell on exit (needed since each
* buffer causes chdir to happen)
*/
if (wdir && *wdir)
strcpy(startdir, wdir);
#endif
edinit(); /* Buffers, windows. */
ttykeymapinit(); /* Symbols, bindings. */
/* Doing update() before reading files causes the error messages from
* the file I/O to show up on the screen(and also an extra display
* of the mode line if there are files specified on the command line).
*/
update();
if ((cp = startupfile(path)) != NULL)
(VOID) load(loadfile = cp);
flag = FALSE;
while (--argc > 0) {
cp = adjustname(*++argv);
curbp = findbuffer(cp);
(VOID) showbuffer(curbp, curwp, 0);
(VOID) readin(cp);
if (fileisrdonly(cp))
curbp->b_flag |= BFVIEW;
cmodename(curbp, cp);
flag = TRUE;
}
thisflag = 0; /* Fake last flags. */
/* got a file so can kill scratch
*/
if (flag)
{
BUFFER *bp;
if (bp = bfind(Scratch, FALSE))
nukebuffer(bp);
}
#ifdef MSW
/* These msgs for my own happiness; however, if not
* here, the insert point incorrectly shows up in col 0
* of the echo line, but it is a display bug only. Don't
* have a clue why though...some kind of timing problem no doubt.
*/
ewprintf("Home dir: %s", homedir);
sleep(1);
if (loadfile)
{
ewprintf("Startup file %s", loadfile);
sleep(1);
}
/* Load any alarms after other startup complete
*/
ReadAlarmFile(homedir, TRUE);
sleep(1);
#endif /* MSW */
/* Check for a crash; can tell if the log file
* was not cleaned up.
*/
ExtendedFunction(function_name(crashcheck));
/* As long as we live...
*/
flag = FALSE;
for(; killed == ALIVE; )
{
*(promptp = prompt) = '\0';
if(epresf == KPROMPT)
eerase();
/* This MUST stay here.. I removed the call from a
* jillion places and put it here (1) because it is
* cleaner and (2) only the active buffer gets - in
* its mode line, others get clear mode lines and so
* we need to update practically all the time. It is cheap
* anyway because the display code is quick enough, and
* really, how many windows do you have up?
*/
upmodes(0);
update();
lastflag = thisflag;
thisflag = 0;
switch(doin()) {
case TRUE:
break;
case ABORT:
ewprintf("Quit"); /* and fall through */
case FALSE:
default:
ttbeep();
macrodef = FALSE;
}
/* interrupted-prompts clear input buffer; reload
* with saved-off events; then check if cwd has changed
*/
CheckForPutback();
switchdir(curbp); /* based on current buffer's file path */
/* update visible buffer list
*/
if ((thisflag & CFKILLB) || (thisflag & CFNEWF) ||
(thisflag & CFNEWB) || (thisflag & CFNEWC))
update_blist();
/* Advertise
*/
if (!flag)
{
ExtendedFunction(function_name(showversion));
flag = TRUE;
}
}
/* Cleanup if all is ok; hard kill means leave inc files
* around, etc. (Not used much, mostly a debugging tool)
*/
if (killed != KILLED)
ExitCleanup();
#ifndef WINDOWED
/* If got good start dir, reset now
*/
if (startdir[0])
setdir(startdir);
#endif
}
/*
* Initialize default buffer and window.
*/
static VOID edinit()
{
register BUFFER *bp;
register EWINDOW *wp;
bheadp = NULL;
bp = bfind(Scratch, TRUE); /* Text buffer. */
wp = (EWINDOW *)calloc(1,sizeof(EWINDOW)); /* Initial window. */
if (bp==NULL || wp==NULL)
panic("edinit");
curbp = bp; /* Current ones. */
wheadp = wp;
curwp = wp;
wp->w_wndp = NULL; /* Initialize window. */
wp->w_bufp = bp;
bp->b_nwnd = 1; /* Displayed. */
wp->w_linep = wp->w_dotp = bp->b_linep;
wp->w_doto = 0;
wp->w_markp = NULL;
wp->w_marko = 0;
wp->w_toprow = 0;
wp->w_ntrows = (char)(nrow-2); /* 2 = mode, echo. */
wp->w_force = 0;
wp->w_flag = WFMODE|WFHARD; /* Full. */
}
/*
* Quit command. If an argument, always
* quit. Otherwise confirm if a buffer has been
* changed and not written out. Normally bound
* to "C-X C-C".
*/
/*ARGSUSED*/
quit(f, n)
int f, n;
{
register int s;
if ((s = anycb(FALSE)) == ABORT)
return ABORT;
if (s == FALSE
|| eyesno("Some modified buffers exist, really exit") == TRUE)
{
vttidy();
#ifdef SYSCLEANUP
SYSCLEANUP;
#endif
killed = DIED;
}
return TRUE;
}
/*
* User abort. Should be called by any input routine that sees a C-g
* to abort whatever C-g is aborting these days. Currently does
* nothing.
*/
/*ARGSUSED*/
ctrlg(f, n)
int f, n;
{
return ABORT;
}
#ifdef JAM_
/* perform the word wrap
*/
dowordwrap(lp, s)
register LINE *lp; /* current line */
register int s; /* cursor offset */
{
register int q;
register int c;
/* seek backwards to whitespace
*/
for (q = s; q >= 0 && (c = lgetc(lp, q)) != ' ' && c != '\t'; q--)
;
if (q < 0) /* can't split this line (no whitespace) */
return;
curwp->w_doto = q;
newline();
lp = curwp->w_dotp;
curwp->w_doto = lp->l_used;
}
#endif
/* return parsed/truncated startup path (app name removed)
*/
char *apppath()
{
return(path);
}
void disable_preload()
{
preload_ = FALSE;
}
void enable_preload()
{
preload_ = TRUE;
}
/* Called before exit to delete temp files; the
* point being if these files remain, then we
* died ungracefully. at some time, need to
* tell user we found them...
*/
void ExitCleanup()
{
register BUFFER *bp;
for (bp = bheadp; bp != NULL; bp = bp->b_bufp)
if (bp->b_iname[0])
unlink(bp->b_iname);
ewprintf("Cleaning up log(s)...");
RemoveIncSaveLog();
}
/* kill emax hard!
*/
int shootmedead(f, n)
int f, n;
{
killed = KILLED;
return(1);
}
/* Support to manage a log of files
* which currently have an incremental save file.
* If we die hard (or the machine does), this
* file will be found next start-up and we
* can warn the user
*/
#define UNSAVED "*Unsaved*"
static void _makename(buf)
char *buf;
{
int j = strlen(homedir);
strcpy(buf, homedir); /* where to look for file */
if (buf[j - 1] != BDC1)
{
buf[j] = BDC1;
buf[j+1] = '\0';
}
strcat(buf, AppName);
strcat(buf, ".inc");
for (j = 0; buf[j] != '\0'; j++)
if (ISUPPER(buf[j]))
buf[j] = (char)TOLOWER(buf[j]);
}
/* Check for existance of crash file on startup
*/
int crashcheck(f, n)
int f,n;
{
char incSaveLog[NFILEN];
_makename(incSaveLog);
if (fileisok(incSaveLog))
{
BUFFER *bp = bfind(incSaveLog, FALSE);
char *adjf;
if (bp)
{
bp->b_flag &= ~(BFCHG | BFINC| BFSAVED);
nukebuffer(bp);
}
AddString(incSaveLog);
AddKchar(CCHR('J'));
poptofilequiet(0, 1);
adjf = adjustname(incSaveLog);
if (bp = findexistingbuffer(adjf))
{
if((bp->b_modes[0] = name_mode(DiredStr)) == NULL)
{
bp->b_modes[0] = &map_table[0];
ewprintf(modeerr, DiredStr);
nukebuffer(bp);
return (FALSE);
}
strcpy(bp->b_bname, UNSAVED);
bp->b_fname[0] = '\0';
bp->b_flag |= (BFVIEW | BFREVERT);
bp->b_nmodes = 0;
}
else
ewprintf("Failed to init incremental log buffer");
}
#if 0 /* Need a way on UN*X to find another process */
WindowMessage("Is another editor already running?\n Backup log found...",
FALSE);
#endif
return(1);
}
/* Create a file in HOME which is a log of all
* buffers which currently have a autosave file (*.%%*).
* Make a line in the file for each buffer which has
* the full path name. We will just display it for the user
* on restart...
*/
void MakeIncSaveLog()
{
register BUFFER *bp;
char incSaveLog[NFILEN];
BOOL opened = FALSE;
char linebuf[NLINE];
for (bp = bheadp; bp != NULL; bp = bp->b_bufp)
if ((bp->b_iname[0]) && (bp->b_flag & BFSAVED))
{
if (!opened)
{
RemoveIncSaveLog(); /* remove existing file now */
_makename(incSaveLog);
if (ffwopen(incSaveLog) != FIOSUC)
{
ewprintf("Can't create incremental save log %s.", incSaveLog);
break;
}
}
opened = TRUE;
/* write the real file name into the log; user can then do
* revert-to on this file
*/
sprintf(linebuf, " %s ", bp->b_fname);
if (ffputline(linebuf, (int)strlen(linebuf)) != FIOSUC)
break; /* incomplete file! gag */
}
if (opened)
ffclose();
else
RemoveIncSaveLog(); /* delete any log since nothing to remember */
}
/* Nice (not crashed/killed) exit calls this and
* we cleanup the log
*/
void RemoveIncSaveLog()
{
char incSaveLog[NFILEN];
_makename(incSaveLog);
unlink(incSaveLog);
}
/* toggle state of show-touched-lines flag
*/
int toggleshowtouched(f,n)
int f,n;
{
showtouchedlines = (showtouchedlines ? FALSE : TRUE);
ewprintf("Touched lines %s be highlite.",
showtouchedlines ? "will" : "will not");
upmodes(WFHARD);
return(TRUE);
}
/*
* All this stuff belongs somewhere else but I didn't
* feel like creating a new file!
*/
#define WILD 99
#define IsWild(n) ((n) == WILD)
#define IsMatch(n, m) (IsWild(n) || ((n) == (m)))
#define ALARM_EXT ".alr"
#define MINLEN (2+1+2+1+2+1+2)
/* alarm def: 00 00 00 00 "" mos,day,hour,min,msg
* 99 means any mon/day/hour
*/
typedef struct _anAlarm
{
struct _anAlarm *next;
BOOL fired;
struct tm theTime;
char *theMessage;
} AnAlarm;
static AnAlarm *s_firstAlarm = (AnAlarm *)0;
#ifdef WINDOWED
/* The X11 version is pretty feeble at this time; it opens
* an empty window and counts on the window manager to
* put up the title. The Windows 3.x/NT version uses a real
* live message box
*/
# ifdef SomeUnix
static char *alarmApp = "xnotalrm ";
# else
static char *alarmApp = "notalarm ";
# endif
#endif
static AnAlarm *rn_(addalarm, (char *s));
static void rn_(freealarms, (void));
static BOOL rn_(loadalarms, (void));
int ManageAlarms(f, n)
int f, n;
{
#ifndef WINDOWED
ewprintf("Alarms not available");
return(TRUE);
#else
char cmd[NLINE * 2];
register int i, s;
BUFFER *bp;
AnAlarm *a;
if ((s = ereply("[a]dd [c]ancel [l]oad [s]show: ", cmd, NLINE)) == TRUE)
{
for (i = 0; cmd[i]; i++)
if (ISUPPER(cmd[i]))
cmd[i] = (char)TOLOWER(cmd[i]);
if (cmd[0] == 'a')
{
s = ereply("mos/day/hour/min/msg (99 99 99 00 ss): ", cmd, NLINE);
if (s == TRUE)
{
i = strlen(cmd) - 1;
while (cmd[i] == ' ')
i--;
if (i >= 0)
cmd[i+1] = 0; /* kill extra blanks at lines end */
if (strlen(cmd) < MINLEN)
s = FALSE;
else
s = ((a = addalarm(cmd)) ? TRUE : FALSE);
}
/* alarm added? if so, add to alarm file
*/
if (s == TRUE)
{
char def[NFILEN];
/* Find existing alarm buffer, else
* create it. Make sure it has a file name.
*/
strcpy(def, g_APPNAME);
strcat(def, ALARM_EXT);
for (i = 0; def[i]; i++)
if (ISUPPER(def[i]))
def[i] = (char)TOLOWER(def[i]);
bp = bfind(def, TRUE);
if (s = (bp ? TRUE : FALSE))
{
if (bp->b_fname[0] == '\0')
{
strcpy(bp->b_fname, homedir);
i = strlen(bp->b_fname);
if (i && (bp->b_fname[i-1] != BDC1))
bp->b_fname[i++] = BDC1;
bp->b_fname[i] = 0;
strcat(bp->b_fname, def);
} /* null buffer name */
sprintf(cmd, " %02d\t%02d\t%02d\t%02d\t%s",
(IsWild(a->theTime.tm_mon) ?
WILD : a->theTime.tm_mon + 1),
a->theTime.tm_mday,
a->theTime.tm_hour,
a->theTime.tm_min,
a->theMessage);
s = (addline(bp, cmd) != NULL) ? TRUE : FALSE;
if (s)
bp->b_flag |= BFCHG;
} /* buffer found */
} /* alarm added */
if (s)
popbuf(bp); /* show buffer if ok */
}
else if (cmd[0] == 'c')
freealarms(); /* zap all alarms */
else if (cmd[0] == 'l')
s = loadalarms(); /* load a new alarm file */
else if (cmd[0] == 's')
{
bp = bfind("*alarms*", TRUE);
s = (bp ? TRUE : FALSE);
if (s)
{
register AnAlarm *a;
bp->b_flag &= ~BFCHG;
bp->b_flag &= ~BFVIEW;
bclear(bp);
addline(bp, "Current alarms");
addline(bp, "--------------");
addline(bp, " Mos\tDay\tHour\tMin\tMsg");
addline(bp, " ---\t---\t----\t---\t---");
for (a = s_firstAlarm; a && s; a = a->next)
{
sprintf(cmd, " %02d\t%02d\t%02d\t%02d\t%s",
(IsWild(a->theTime.tm_mon) ?
WILD : a->theTime.tm_mon + 1),
a->theTime.tm_mday,
a->theTime.tm_hour,
a->theTime.tm_min,
a->theMessage);
s = (addline(bp, cmd) != NULL) ? TRUE : FALSE;
}
bp->b_flag |= BFVIEW;
bp->b_flag &= ~BFCHG;
s = (popbuf(bp) ? TRUE : FALSE);
}
}
else
s = FALSE;
}
return(s);
#endif
}
void AnyPendingAlarms()
{
#ifdef WINDOWED
register AnAlarm *a;
char msg[NLINE];
long currtime;
struct tm *t;
time(&currtime);
t = localtime(&currtime);
for (a = s_firstAlarm; a; a = a->next)
{
if (IsMatch(a->theTime.tm_mon, t->tm_mon) &&
IsMatch(a->theTime.tm_mday, t->tm_mday) &&
IsMatch(a->theTime.tm_hour, t->tm_hour) &&
(a->theTime.tm_min == t->tm_min) &&
!a->fired)
{
a->fired = TRUE;
strcpy(msg, alarmApp);
strcat(msg, a->theMessage);
if (!winspawn(msg, TRUE))
{
/* dump this message and give up
*/
char buffer[512];
sprintf(buffer, "Alarm failed: %s", a->theMessage);
WindowMessage(buffer, FALSE);
break;
}
}
}
#endif
}
static int ReadAlarmFile(dir, append)
char *dir;
BOOL append;
{
#ifdef WINDOWED
char alarmfile[NFILEN];
char c;
int i;
register BUFFER *bp;
register LINE *lp;
alarmfile[0] = '\0'; /* init empty string */
if (s_firstAlarm)
if (eyesno("Cancel existing alarms") == TRUE)
freealarms();
if (append) /* build name with dir */
{
if (dir)
{
int i;
strcpy(alarmfile, dir);
i = strlen(alarmfile) - 1;
if (alarmfile[i] != BDC1)
{
i++;
alarmfile[i++] = BDC1;
alarmfile[i] = '\0';
}
}
strcat(alarmfile, g_APPNAME);
strcat(alarmfile, ALARM_EXT);
}
else /* full name supplied */
strcpy(alarmfile, dir);
for (i = 0; alarmfile[i]; i++)
if (ISUPPER(alarmfile[i]))
alarmfile[i] = (char)TOLOWER(alarmfile[i]);
if (access(alarmfile, F_OK) == 0)
{
AddString(alarmfile);
AddKchar(CCHR('J'));
if (poptofilehidden(0, 1) != TRUE)
return (FALSE);
bp = curbp;
/* parse it
*/
lp = lforw(bp->b_linep);
for (; lp != bp->b_linep; lp = lforw(lp))
{
c = lgetc(lp, 0);
if ((c == ';') || (strlen(ltext(lp)) < MINLEN))
continue;
if (!addalarm(ltext(lp)))
{
ewprintf("Alarm error [%s]", ltext(lp));
return (FALSE);
}
}
/* kill the window if created automagically
*/
if (append)
{
delwind(1, 0);
nukebuffer(bp);
bp = (BUFFER *)0;
}
ewprintf("%s loaded.", alarmfile);
return (TRUE);
}
#endif
return (FALSE);
}
#ifdef WINDOWED
/* Adds alarm to list. Memory not freed up
* by this code; task exit assumed to
* provide cleanup or memory freed when alarms cleared.
*/
static AnAlarm *addalarm(l)
char *l;
{
AnAlarm *a, *tmp;
char *p, *f = "%d";
long currtime;
char *notOK = (char *)0;
struct tm timestruct, *tm;
char msg[NLINE];
time(&currtime);
tm = localtime(&currtime);
timestruct = *tm; /* use some info from sys clock */
strcpy(msg, l);
p = msg;
while(*p && ISWHITE(*p)) p++;
sscanf(p, f, ×truct.tm_mon);
while(*p && !ISWHITE(*p)) p++;
while(*p && ISWHITE(*p)) p++;
sscanf(p, f, ×truct.tm_mday);
while(*p && !ISWHITE(*p)) p++;
while(*p && ISWHITE(*p)) p++;
sscanf(p, f, ×truct.tm_hour);
while(*p && !ISWHITE(*p)) p++;
while(*p && ISWHITE(*p)) p++;
sscanf(p, f, ×truct.tm_min);
while(*p && !ISWHITE(*p)) p++;
while(*p && ISWHITE(*p)) p++;
if (timestruct.tm_mon != WILD)
timestruct.tm_mon -= 1; /* mos from 0 to 11 */
if (timestruct.tm_mon != WILD)
if ((timestruct.tm_mon < 0) || (timestruct.tm_mon > 11))
notOK = "month";
if (!notOK)
if (timestruct.tm_mday != WILD)
if ((timestruct.tm_mday < 0) || (timestruct.tm_mday > 30))
notOK = "day";
if (!notOK)
if (timestruct.tm_hour != WILD)
if ((timestruct.tm_hour < 0) || (timestruct.tm_hour > 23))
notOK = "hour";
if (!notOK)
if ((timestruct.tm_min < 0) || (timestruct.tm_min > 59))
notOK = "minute";
if (notOK)
{
ewprintf("Error in alarm %s [%s]", notOK, l);
return((AnAlarm *)0);
}
/* get new struct
*/
a = (AnAlarm *)calloc(1, sizeof(AnAlarm));
if (!s_firstAlarm)
s_firstAlarm = a;
else
{
for( tmp = s_firstAlarm; tmp->next; tmp = tmp->next)
;
tmp->next = a;
}
a->theTime = timestruct;
if (!(p && *p))
p = "[no message]";
a->theMessage = (char *)malloc(strlen(p) + 1);
strcpy(a->theMessage, p);
return (a);
}
static BOOL loadalarms()
{
char fname[NFILEN];
int s;
if ((s = ereply("Load alarm file: ", fname, NFILEN)) == TRUE)
s = ReadAlarmFile(fname, FALSE);
return (s);
}
static void freealarms()
{
register AnAlarm *a, *tmp;
if (a = s_firstAlarm)
{
for (; a; )
{
tmp = a->next; /* next alarm */
if (a->theMessage)
free(a->theMessage);
free(a);
a = tmp;
}
s_firstAlarm = (AnAlarm *)0;
ewprintf("Alarms cleared.");
}
else
ewprintf("No alarms set.");
}
#endif /* WINDOWED */